home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / DCLAP 6d / dclap6d / DClap / DList.cpp < prev    next >
Text File  |  1996-07-05  |  11KB  |  522 lines

  1. // DList.cp
  2. // This code owes it's structure in large part to Apple's MacApp UList unit
  3. // however, d.gilbert has substatially rewritten it.
  4.  
  5.  
  6. #include <ncbi.h>
  7. #include <dgg.h>
  8. #include "DList.h"
  9.  
  10.  
  11. static const short kArrayIncrement = 6;         
  12.  
  13. typedef    DObject* DObjectPtr;
  14.  
  15.  
  16. // class DArray
  17.  
  18.  
  19. DArray::DArray(short itemSize, long initialSize)
  20. {
  21.   SetClass("DArray",sizeof(DArray));
  22.     fArraySize = kEmptySize;
  23.     fArrayIncrement = kArrayIncrement;
  24.     fSize = kEmptySize;
  25.     fArrayStore = NULL;
  26.  
  27.     fItemSize = itemSize;
  28.     fItemSizeShift = 0;
  29.     if (odd(itemSize)) ++itemSize; // make sure we have even size for shifting
  30.     while (((itemSize - 1) >> fItemSizeShift) > 0) ++fItemSizeShift;
  31.     this->SetArraySize(initialSize);
  32.  
  33. DArray::~DArray()
  34. {
  35.     fArrayStore= MemFree(fArrayStore);
  36. }  
  37.  
  38. void DArray::DeleteAll()
  39. {
  40.     if (fSize > kEmptySize) this->DeleteItemsAt(0, fSize); //1,fSize
  41.  
  42. DObject* DArray::Clone()
  43. {
  44.     DArray* result = (DArray*) DObject::Clone();
  45.     result->fArrayStore= MemDup(fArrayStore,  (ulong) (fArraySize << fItemSizeShift));
  46.     return result;
  47. }
  48.  
  49. void* DArray::ComputeAddress(long index)
  50. {
  51.     return (void*) ((char*)fArrayStore + (index << fItemSizeShift)); 
  52. }  
  53.  
  54.  
  55.  
  56. void DArray::DeleteItemsAt(long index, long count)
  57. {
  58.     VoidPtr indexPtr, nextItemPtr, lastItemPtr;
  59.     long countBytes;
  60.  
  61.     countBytes = count << fItemSizeShift;
  62.     indexPtr = this->ComputeAddress(index);
  63.     nextItemPtr = this->ComputeAddress(index + count);
  64.     lastItemPtr = this->ComputeAddress(fSize); //1based: + 1);
  65.  
  66.     if (nextItemPtr < lastItemPtr)        
  67.         MemMove(indexPtr, nextItemPtr, (long)lastItemPtr - (long)nextItemPtr);
  68.  
  69.     this->SetArraySize(fSize - count);        
  70.     fSize -= count;
  71. }   
  72.  
  73.  
  74.  
  75.  
  76. void DArray::GetItemsAt(long index, void* itemPtr, long count)
  77. {
  78.     if (count > kEmptySize)
  79.         MemMove( itemPtr, this->ComputeAddress(index), 
  80.             ((count - 1) << fItemSizeShift) + fItemSize);         
  81. }  
  82.  
  83.  
  84. void DArray::ReplaceItemsAt(long index, void* itemPtr, long count)
  85. {
  86.     VoidPtr indexPtr= this->ComputeAddress(index);
  87.     long countBytes= count << fItemSizeShift;
  88.     MemMove( indexPtr, itemPtr, countBytes);
  89.  
  90.  
  91. void DArray::InsertItemsBefore(long index, void* itemPtr, long count)
  92. {
  93.     VoidPtr indexPtr, nextIndexPtr, lastItemPtr;
  94.     long countBytes;
  95.  
  96.     this->SetArraySize(fSize + count);                 
  97.     indexPtr = this->ComputeAddress(index);
  98.     nextIndexPtr = this->ComputeAddress(index + count);
  99.     lastItemPtr = this->ComputeAddress(fSize);    //1based: fSize + 1
  100.     countBytes = count << fItemSizeShift;
  101.  
  102.     if (index < fSize)        //1based: <=             
  103.         MemMove( nextIndexPtr, indexPtr, (long)lastItemPtr - (long)indexPtr);
  104.  
  105.     if ((countBytes == sizeof(long)) && !odd((long)itemPtr) && !odd((long)indexPtr))
  106.         *((long*)indexPtr) = *((long*)itemPtr);        // shortcut for longs 
  107.     else
  108.         MemMove(indexPtr, itemPtr, countBytes); 
  109.  
  110.     fSize += count;
  111. }  
  112.  
  113.  
  114.  
  115.  
  116. void DArray::SetArraySize(long theSize)
  117. {
  118.     long newSize;
  119.     
  120.     if ((theSize > fArraySize) || (fArraySize - theSize >= fArrayIncrement)) {
  121.         if (fArrayIncrement)
  122.             newSize = (theSize + fArrayIncrement) 
  123.                                 - (theSize + fArrayIncrement) % fArrayIncrement;
  124.         else
  125.             newSize = theSize;
  126.         if (newSize != fArraySize)  {
  127.             ulong chunk= (ulong) (newSize << fItemSizeShift);
  128.             if (fArrayStore == NULL) fArrayStore = MemNew( chunk);
  129.             else fArrayStore= MemMore(fArrayStore, chunk);
  130.             }
  131.         fArraySize = newSize;
  132.       }
  133.  
  134.  
  135. long DArray::Search(CompareFunc compare, void *itemPtr)
  136. {
  137.     register char*  itemAt = (char*) fArrayStore;
  138.     long     itemsize= 1 << fItemSizeShift;
  139.         
  140.         // speed this up w/ a bisection method == start in middle & bounce around ??
  141.         // NO -- can't assume this array is SORTED !!
  142. #if 0
  143.     long lo, hi, mid;
  144.     short cmp;
  145.     lo= 0; 
  146.     hi= fSize;
  147.     do {
  148.         mid= (hi+lo) >> 1;  // div 2;
  149.         itemAt= (char*) fArrayStore + mid * itemsize;
  150.         cmp= (*compare)( itemPtr, itemAt);
  151.         if (cmp == 0) return mid;
  152.         else if (cmp > 0) lo= mid;
  153.         else hi= mid;
  154.     } while (hi > lo+1);
  155.     
  156.     if (mid != hi) {
  157.         itemAt= (char*) fArrayStore + hi * itemsize;
  158.         cmp= (*compare)( itemPtr, itemAt);
  159.         if (cmp == 0) return hi;
  160.         }
  161.     else if (mid != lo) {
  162.         itemAt= (char*) fArrayStore + lo * itemsize;
  163.         cmp= (*compare)( itemPtr, itemAt);
  164.         if (cmp == 0) return lo;
  165.         }
  166.     return kEmptyIndex;
  167. #else
  168.     register long i;
  169.     for (i = 0; i < fSize; i++) {
  170.         if ( (*compare)( itemPtr, itemAt) == 0) 
  171.             return i;
  172.         itemAt += itemsize;
  173.         }
  174.     return kEmptyIndex;
  175. #endif
  176. }     
  177.  
  178.  
  179.  
  180.  
  181.  
  182.  
  183.  
  184. // class DList
  185.  
  186. // default fCompareFunc
  187. short DefaultCompare(void* item1, void* item2)
  188. {
  189.     if ((unsigned long) item1 > (unsigned long) item2)
  190.         return 1;
  191.     else if ((unsigned long) item1 < (unsigned long) item2)
  192.         return -1;
  193.     else
  194.         return 0;
  195.  
  196.  
  197. DList::DList(CompareFunc itsComparer, short options): 
  198.     DArray(sizeof(DObject*), kEmptySize)
  199. {
  200.   SetClass("DList",sizeof(DList));
  201.     if (itsComparer) fCompareFunc= itsComparer;
  202.     else fCompareFunc= ::DefaultCompare;
  203.     fOwnObjects= options & kOwnObjects;
  204.     fDeleteObjects = options & kDeleteObjects;        
  205.  
  206. DList::~DList()
  207. {
  208.     if (fDeleteObjects) this->FreeAllObjects();
  209.  
  210.         
  211. DObject* DList::At(long index)
  212. {
  213.     //return (*this)[index];
  214.     if (index<0 || index>=fSize) return NULL;
  215.     DObject** vp= (DObject**) ((char*)fArrayStore + (index << fItemSizeShift)); 
  216.     if (vp) return *vp;
  217.     else return NULL;
  218.  
  219.  
  220.  
  221. void DList::FreeAllObjects()
  222. {
  223.     long i, n= this->GetSize();
  224.     for (i= 0; i<n; i++) {
  225.         DObject* obj= At(i);
  226.         if (obj) {
  227.           if (obj->GetOwnerCount() <= 1) delete obj; 
  228.               // ^^^^ BIG MEM LEAK !! THIS delete DOESN"T CALL DESTRUCTOR !
  229.           else obj->suicide(); // this alone doens't call obj destructors !!
  230.           }
  231.         }
  232.     this->DeleteAll();
  233.  
  234.  
  235. long DList::GetEqualItemNo(DObject* item)
  236. {
  237.     long index;
  238.  
  239.     if (item == NULL) return kEmptyIndex;
  240.     index = this->Search( fCompareFunc, &item);
  241.     return index;  // == kEmptyIndex if no match
  242.  
  243.  
  244.  
  245. #if 1
  246. // choose your sort
  247.  
  248. void DList::QuickSort(long beginIndex, long endIndex, CompareFunc CompareItems)
  249. // recursive qs
  250. {
  251.     long i, j;
  252.      DObjectPtr    iobj, jobj, endobj;
  253.      
  254.     if (beginIndex < endIndex) {
  255.         i = beginIndex; 
  256.         j = endIndex;  
  257.         endobj= this->At(endIndex);
  258.         do {
  259.             iobj= this->At(i);            
  260.             while (i < j && CompareItems( iobj, endobj) <= 0) 
  261.                 iobj= this->At(++i);            
  262.             jobj= this->At(j);
  263.             while (j > i && CompareItems( jobj, endobj) >= 0) 
  264.                 jobj= this->At(--j);
  265.             if (i<j) {    // swap
  266.                 this->ReplaceItemsAt(i, &jobj, 1); //was &     
  267.                 this->ReplaceItemsAt(j, &iobj, 1); //was &     
  268.                 }
  269.         } while (i < j);
  270.         
  271.          this->ReplaceItemsAt(i, &endobj, 1);  
  272.         this->ReplaceItemsAt(endIndex, &iobj, 1);  
  273.         if (i - beginIndex < endIndex - i) {
  274.             QuickSort( beginIndex, i-1, CompareItems);
  275.           QuickSort( i+1, endIndex, CompareItems);
  276.           }
  277.         else {
  278.             QuickSort( i+1, endIndex, CompareItems);
  279.              QuickSort( beginIndex, i-1, CompareItems);
  280.              }
  281.         }
  282. }
  283.  
  284. long DList::QSPartition(long beginIndex, long endIndex,     
  285.                                    CompareFunc CompareItems)
  286. {
  287.     return 0;
  288. }
  289.  
  290. long DList::QSRandomPartition(long beginIndex, long endIndex,     
  291.                                    CompareFunc CompareItems)
  292. {
  293.     return 0;
  294. }
  295.  
  296.  
  297. #else
  298. // this was Apple's algorithm
  299.  
  300. void DList::QuickSort(long beginIndex, long endIndex, CompareFunc CompareItems)
  301. {
  302.     if (beginIndex < endIndex) {
  303.         long left = this->QSRandomPartition(beginIndex, endIndex, CompareItems);
  304.         this->QuickSort(beginIndex, left, CompareItems);
  305.         this->QuickSort(left+1, endIndex, CompareItems);     
  306.     }
  307.  
  308.  
  309. long DList::QSPartition(long beginIndex, long endIndex, CompareFunc CompareItems)
  310. {
  311.     if (beginIndex >= endIndex)
  312.         return endIndex;
  313.     {
  314.         DObjectPtr pivot = this->At(beginIndex);                // x
  315.         long i = beginIndex - 1;    // p - 1
  316.         long j = endIndex + 1;    // r + 1
  317.         while (true)
  318.         {
  319.             DObjectPtr secondKey;
  320.             do
  321.             {
  322.                 --j;
  323.                 secondKey = this->At(j);    // A[j]
  324.             } while (CompareItems( pivot, secondKey) <= -1);
  325.             do
  326.             {
  327.                 ++i;
  328.                 secondKey = this->At(i);    // A[i]
  329.             } while (CompareItems( pivot, secondKey) >= 1);
  330.             if (i < j)
  331.             {    // Swap the Items
  332.                 DObjectPtr leftObject = this->At(i);
  333.                 DObjectPtr rightObject = this->At(j);
  334.                 this->ReplaceItemsAt(i, &rightObject, 1); // was &
  335.                 this->ReplaceItemsAt(j, &leftObject, 1); //was &
  336.             }
  337.             else
  338.                 return j;
  339.         }
  340.     }
  341.  
  342.  
  343. long RandomArrayIndex(long beginIndex, long endIndex)
  344. {
  345.     if (beginIndex == endIndex) return beginIndex;
  346.     //long randomValue = rand() % labs(endIndex - beginIndex);// labs() not found by g++
  347.     long randomValue = endIndex - beginIndex;
  348.     if (randomValue < 0) randomValue = -randomValue;
  349.     randomValue= rand() % randomValue;
  350.     return beginIndex + randomValue;
  351. }
  352.  
  353. long DList::QSRandomPartition(long beginIndex, long endIndex, CompareFunc CompareItems )
  354. {
  355.     long i = RandomArrayIndex(beginIndex, endIndex);
  356.     
  357.     // exchange
  358.     DObjectPtr beginIndexObject = this->At(beginIndex);
  359.     DObjectPtr ithObject = this->At(i);
  360.     this->ReplaceItemsAt(beginIndex, &ithObject, 1); //was &    // A[beginIndex] = A[i]
  361.     this->ReplaceItemsAt(i, &beginIndexObject, 1); //was &    // A[i] = A[beginIndex]
  362.  
  363.     return this->QSPartition(beginIndex, endIndex, CompareItems);
  364.  
  365. #endif
  366.  
  367.  
  368. void DList::Sort()
  369. {
  370.     if (this->GetSize() > 0)
  371.         this->QuickSort(0, fSize-1, fCompareFunc); // was 1,fsize
  372.  
  373. void DList::SortBy(CompareFunc CompareItems)
  374. {
  375.     if (this->GetSize() > 0)
  376.         this->QuickSort(0, fSize-1, CompareItems); // was 1,fsize
  377.  
  378.  
  379. void DList::AtDelete(long index)
  380. {
  381.     if (fDeleteObjects)  At(index)->suicide(); //delete At(index); 
  382.         // ^^ this will make a mess of Pop() and Dequeue() method results, who call here
  383.     this->DeleteItemsAt(index, 1);
  384. }
  385.  
  386. void DList::Delete(DObject* item)
  387. {
  388.     long index;
  389.     if (item == NULL) return;
  390.     index = this->GetIdentityItemNo(item);
  391.     if (index != kEmptyIndex) this->AtDelete(index);
  392.  
  393.  
  394. DObject* DList::First()
  395. {
  396.     if (fSize <= kEmptySize)
  397.         return NULL;
  398.     else
  399.         return this->At(0); //1based: 1
  400.  
  401. DObject* DList::Last()
  402. {
  403.     if (fSize <= kEmptySize)
  404.         return NULL;
  405.     else
  406.         return this->At(fSize-1);
  407. }  
  408.  
  409.  
  410. long DList::GetIdentityItemNo(DObject* item)
  411. {
  412.     if (item == NULL) return kEmptyIndex;
  413.     long i, n= this->GetSize();
  414.     for (i= 0; i<n; i++) if (At(i) == item) return i;
  415.     return kEmptyIndex; 
  416.  
  417.  
  418. void DList::AtPut(long index, DObject* newItem)
  419. {
  420.     if (fOwnObjects && newItem) newItem->newOwner();
  421.     this->ReplaceItemsAt( index, &newItem, 1); //was &newItem
  422.  
  423.  
  424. void DList::InsertBefore(long index, DObject* item)
  425. {
  426.     if (fOwnObjects && item) item->newOwner();
  427.     this->InsertItemsBefore(index, &item, 1); // was &item !!!
  428. }
  429.  
  430.  
  431. void DList::InsertInOrder(DObject* item)
  432. {
  433.     long index= Search( fCompareFunc, &item);
  434.     if (index > kEmptyIndex)
  435.         InsertBefore( index, item);
  436.     else
  437.         InsertBefore( fSize, item);
  438.  
  439. void DList::InsertFirst(DObject* item)
  440. {
  441.     this->InsertBefore(0, item); //1
  442.  
  443. void DList::InsertLast(DObject* item)
  444. {
  445.     this->InsertBefore(fSize, item); // + 1
  446.  
  447.  
  448. void DList::Push(DObject* item)
  449. {
  450.     this->InsertLast(item);
  451.  
  452. DObject* DList::Pop()
  453. {
  454.     DObject* topOfStack;
  455.  
  456.     if (fSize <= kEmptySize)
  457.         topOfStack = NULL;
  458.     else {
  459.         topOfStack = this->At(fSize-1);
  460.         //this->AtDelete(fSize-1);
  461.         this->DeleteItemsAt(fSize-1, 1);     // this bypasses fDeleteObjects check ...
  462.         }
  463.     return topOfStack;
  464.  
  465.  
  466.  
  467. void DList::Queue(DObject* item)
  468. {
  469.     this->InsertLast(item);
  470.  
  471. DObject* DList::Dequeue()
  472. {
  473.     DObject* beginningOfStack;
  474.  
  475.     if (fSize <= kEmptySize)
  476.         beginningOfStack = NULL;
  477.     else {
  478.         beginningOfStack = this->At(0);    //1based: 1
  479.         //this->AtDelete(0);                 //1based: 1
  480.         this->DeleteItemsAt(0, 1);     // this bypasses fDeleteObjects check ...
  481.         }
  482.     return beginningOfStack;
  483.  
  484.  
  485.  
  486.  
  487.  
  488. DList*    FreeListIfObject(DList* aList)
  489. {
  490.     if (aList) {
  491.         //aList->FreeAllObjects(); // destructor now calls FreeAllObjects()
  492.         delete aList; 
  493.         }
  494.     return NULL;
  495. }
  496.